package analysis;

import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Iterator;

import database.CSdb;

import objects.DistanceLog;
import objects.GeneralLog;
import objects.SpeedLogReport;
import objects.StopSignLog;
import objects.Student;

public class Reports {

    private Student driver;
    private CSdb csdatabase;
    private ArrayList<SpeedLogReport> speedlogs;
    private ArrayList<DistanceLog> distancelogs;
    private ArrayList<StopSignLog> stoplogs;
    private ArrayList<Student> students;
    private ArrayList<GeneralLog> seatbeltlogs;
    private ArrayList<Record> records;
    private Double ptsPerHour;
    private Double totDriverPts;
  
    public Reports() {

    	driver = new Student();
        speedlogs = new ArrayList<SpeedLogReport>();
    	distancelogs = new ArrayList<DistanceLog>();
    	stoplogs = new ArrayList<StopSignLog>();
    	setStudents(new ArrayList<Student>());
    	seatbeltlogs = new ArrayList<GeneralLog>();
    	records = new ArrayList<Record>();
    	ptsPerHour = 0.0;
    	totDriverPts = 0.0;
    }

    public void generateReport(Integer driverID) {

        Calendar cal = Calendar.getInstance();
        Calendar cal2 = Calendar.getInstance();
        cal2.set(Calendar.HOUR_OF_DAY, 0);
        cal2.set(Calendar.MINUTE, 0);
        cal2.set(Calendar.SECOND, 0);
        cal2.set(Calendar.MILLISECOND,0);

        long current=cal.getTimeInMillis();
        long previous = cal2.getTimeInMillis();

        Timestamp uplimit = new Timestamp(current);
        Timestamp downlimit = new Timestamp(previous);

        driver.setID(driverID);
        retreiveData(driver.getID());

        Timestamp overalldown = new Timestamp(downlimit.getTime()-6*86400000);
        System.out.println("Name: " + driver.getName());
        System.out.println("Dates Captures: " + uplimit + " to " + overalldown);
        System.out.println();

        for (int i =0; i<7;i++) {
        	generateDaily(uplimit,downlimit);
        	current=previous;
        	previous=previous-86400000;
        	uplimit.setTime(current);
        	downlimit.setTime(previous);
        }
	
		calculatePtsPerHour();
	
		displayRecords();
    }

    public void generateDaily(Timestamp uplimit, Timestamp downlimit) {
	
		ArrayList<StopSignLog> dailystoplogs = new ArrayList<StopSignLog>();
        Iterator<StopSignLog> stopitr = stoplogs.iterator();
        
        while (stopitr.hasNext()) {
			StopSignLog stlog = stopitr.next();
	
			if ( (stlog.getTimeSt().before(uplimit)) && (stlog.getTimeSt().after(downlimit)) ) {
				dailystoplogs.add(stlog);
			}
        }

        ArrayList<GeneralLog> dailyseatlogs = new ArrayList<GeneralLog>();
        Iterator<GeneralLog> seatitr = seatbeltlogs.iterator();
        while (seatitr.hasNext()) {
                GeneralLog seatlog = seatitr.next();

                if ( (seatlog.getTimeSt().before(uplimit)) && (seatlog.getTimeSt().after(downlimit)) ) {
                        dailyseatlogs.add(seatlog);
                }
        }

        ArrayList<DistanceLog> dailydistancelogs = new ArrayList<DistanceLog>();
        Iterator<DistanceLog> distitr = distancelogs.iterator();
        while (distitr.hasNext()) {
                DistanceLog distlog = distitr.next();

                if ( (distlog.getTimeSt().before(uplimit)) && (distlog.getTimeSt().after(downlimit)) ) {
                        dailydistancelogs.add(distlog);
                }
        }
 
        ArrayList<SpeedLogReport> dailyspeedlogs = new ArrayList<SpeedLogReport>();
        Iterator<SpeedLogReport> speeditr = speedlogs.iterator();
        while (speeditr.hasNext()) {
                SpeedLogReport speedlog = speeditr.next();

                if ( (speedlog.getTimeSt().before(uplimit)) && (speedlog.getTimeSt().after(downlimit)) ) {
                        dailyspeedlogs.add(speedlog);
                }
        }

		calculateStopSignStats(dailystoplogs,downlimit);
		calculateSeatBeltStats(dailyseatlogs,downlimit);
		calculateDistanceStats(dailydistancelogs,downlimit);
		calculateSpeedStats(dailyspeedlogs,downlimit);
		System.out.println();

    }
 
    public void retreiveData(Integer driverID) 
    {
		driver.setID(driverID);
		
		try {
			csdatabase = new CSdb();
		} catch (Exception exc){
	        	System.out.println("Could not connect to DB");
	            exc.printStackTrace();
	    }
	
        try {
        	csdatabase.getStudent(driver);
        } catch (SQLException e) {
        	System.out.println("Could not get Driver information" + e.getMessage());
        	csdatabase.close();
        	e.printStackTrace();
        }

		try {
			csdatabase.getStopLogsbyStID(stoplogs,driver.getID());
		}
		catch (java.sql.SQLException sqlexc) {
			System.out.println("Could not fetch the StopSign Logs");
			csdatabase.close();
			System.exit(1);
		}

        try {
                csdatabase.getDistanceLogsbyStID(distancelogs,driver.getID());
        } catch (SQLException e) {
                System.out.println("Could not fetch the Distance Logs"+ e.getMessage());
                csdatabase.close();
                e.printStackTrace();
                System.exit(1);
        }

        try {
                csdatabase.getGeneralLogsbyStID(seatbeltlogs,driver.getID());
        }
        catch (java.sql.SQLException sqlexc) {
                System.out.println("Could not fetch the SeatBelt Logs"+ sqlexc.getMessage());
		csdatabase.close();
                System.exit(1);
        }


        try {
                csdatabase.getSpeedLogsbyStID(speedlogs,driver.getID());
        }
        catch (java.sql.SQLException sqlexc) {
                System.out.println("Could not fetch the Speed Logs"+ sqlexc.getMessage());
                csdatabase.close();
                System.exit(1);
        }
	
	csdatabase.close();

    }

    public void calculateStopSignStats(ArrayList<StopSignLog> stoplogs, Timestamp timest){

        //Double driverPoints;
        StopSignRecord stoprecord = new StopSignRecord();

        stoprecord.setDate(timest.getTime());
        stoprecord.setFrequency(stoplogs.size());
        stoprecord.setType("Stop Sign");
        stoprecord.setWeight(0.057);
        stoprecord.setPoints(stoprecord.getWeight()*stoprecord.getFrequency());

        Iterator<StopSignLog> stopitr = stoplogs.iterator();
        while (stopitr.hasNext()) {
                StopSignLog slog = stopitr.next();
                stoprecord.getStoplogs().add(slog);
        }

        if(stoprecord.getFrequency() != 0 && stoprecord.getPoints() != 0) {
        	records.add(stoprecord);
        }
        stoprecord.display();
    }

    public void calculateSeatBeltStats(ArrayList<GeneralLog> genlogs, Timestamp timest){

        //Double driverPoints;
        SeatbeltRecord seatbeltrecord = new SeatbeltRecord();
        
        seatbeltrecord.setDate(timest.getTime());
        seatbeltrecord.setFrequency(genlogs.size());
        seatbeltrecord.setType("Seat Belt");
        seatbeltrecord.setWeight(0.079);

        Iterator<GeneralLog> genitr = genlogs.iterator();
        while (genitr.hasNext()) {
        	GeneralLog glog = genitr.next();
                seatbeltrecord.setDuration(seatbeltrecord.getDuration() + glog.getDuration());
                seatbeltrecord.getSeatbeltlogs().add(glog);
	}
        seatbeltrecord.setPoints((seatbeltrecord.getDuration()/3600000.0)*seatbeltrecord.getWeight());
        
        if(seatbeltrecord.getDuration() != 0 && seatbeltrecord.getFrequency() != 0 && seatbeltrecord.getPoints() != 0) {
        	records.add(seatbeltrecord);
        }
        
        seatbeltrecord.display();
    }


    public void calculateDistanceStats(ArrayList<DistanceLog> distlogs, Timestamp timest){

        //Double driverPoints;
        DistanceRecord distancerecord = new DistanceRecord();
        
        distancerecord.setDate(timest.getTime());
        distancerecord.setFrequency(distlogs.size());
        distancerecord.setType("Following Too Closely");
        distancerecord.setWeight(0.042);

        Iterator<DistanceLog> distitr = distlogs.iterator();
        while (distitr.hasNext()) {
                DistanceLog dlog = distitr.next();
                distancerecord.setDuration(distancerecord.getDuration() + dlog.getDuration());
                distancerecord.getDistancelogs().add(dlog);
        }
        distancerecord.setPoints((distancerecord.getDuration()/3600000.0)*distancerecord.getWeight());
        
        if(distancerecord.getDuration() != 0 && distancerecord.getFrequency() != 0 && distancerecord.getPoints() != 0) {
        	records.add(distancerecord);
        }
        
        distancerecord.display();
    }


    public void calculateSpeedStats(ArrayList<SpeedLogReport> speedlogs, Timestamp timest){

        Double driverPoints;
        SpeedRecord speedrecord = new SpeedRecord();
        
        speedrecord.setDate(timest.getTime());
        speedrecord.setFrequency(speedlogs.size());
        speedrecord.setType("Speeding");
        speedrecord.setWeight(0.821);
       
        Iterator<SpeedLogReport> speeditr = speedlogs.iterator();
        while (speeditr.hasNext()) {
               SpeedLogReport splogrep = speeditr.next();
               speedrecord.setDuration(speedrecord.getDuration() + splogrep.getDuration());

               driverPoints = (((splogrep.getDuration()/3600000.0) * 0.821)* ((splogrep.getCurrSpeed() - splogrep.getSpeedLimit())/ splogrep.getSpeedLimit())
                                 + (splogrep.getDuration()/3600000.0)) * 0.821;
               speedrecord.setPoints(speedrecord.getPoints()+driverPoints);
               speedrecord.getSpeedlogs().add(splogrep);
        }
        
        if(speedrecord.getDuration() != 0 && speedrecord.getFrequency() != 0 && speedrecord.getPoints() != 0) {
        	records.add(speedrecord);
        }
        speedrecord.display();
    }
    
    public void calculatePtsPerHour() {
    	Double driverPts = 0.0;
    	Iterator<Record> recitr = records.iterator();
    	while(recitr.hasNext()){
    		Record record = recitr.next();
    		driverPts += record.getPoints();
    	}
    	
    	totDriverPts = driverPts;
    	
    	if (driver.getHours() != 0) {
		    	ptsPerHour = totDriverPts/driver.getHours();
		} else {
			ptsPerHour = 0.0;
		}
	    
    	System.out.println("Points Per Hour: " + ptsPerHour);
    }

    public void displayRecords(){
    	Iterator<Record> recitr = records.iterator();
	
	Integer sizerecords = records.size();
	System.out.println("Size of the records is: " + sizerecords);

    	while(recitr.hasNext()){
    		Record record = recitr.next();
    		record.displayLogs();
		//System.out.println();
    	}
    }
	
    public void displayRecord(Integer id) {
	records.get(id).displayLogs();
    }
    
    public void setPtsPerHour(Double ptsPerHour){
    	this.ptsPerHour = ptsPerHour;
    }
    
    public Double getPtsPerHour(){
    	return ptsPerHour;
    }
    
    public void setTotDriverPts(Double totDriverPts){
    	this.totDriverPts = totDriverPts;
    }
    
    public Double getTotDriverPts(){
    	return totDriverPts;
    }
    
	public void setStudents(ArrayList<Student> students) {
		this.students = students;
	}


	public ArrayList<Student> getStudents() {
		return students;
	}
	
	public void setRecords(ArrayList<Record> records) {
		this.records = records;
	}


	public ArrayList<Record> getRecords() {
		return records;
	}

}
